package com.htthorizon.model.controller;

import java.io.IOException;
import com.htthorizon.system.api.exception.NotDeptException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.htthorizon.aop.annotation.Operate;
import com.htthorizon.common.core.utils.StringUtils;
import com.htthorizon.datascope.DataScopeUtil;
import com.htthorizon.model.domain.ModelSource;
import com.htthorizon.model.enums.OperateType;
import com.htthorizon.system.api.exception.DownloadOverException;
import com.htthorizon.model.request.ModelSearchReq;
import com.htthorizon.model.response.RemoteDataInfoDto;
import com.htthorizon.model.service.IModelInfoService;
import com.htthorizon.model.service.IModelMetaService;
import com.htthorizon.model.service.IModelSourceService;
import com.htthorizon.util.SDKGetAPIUtil;
import com.htthorizon.util.ServiceMarket2HTTPUtil;
import com.htthorizon.util.ServiceMarketHTTPUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import com.htthorizon.common.log.annotation.Log;
import com.htthorizon.common.log.enums.BusinessType;
import com.htthorizon.common.security.annotation.RequiresPermissions;
import com.htthorizon.model.domain.ModelSearch;
import com.htthorizon.model.service.IModelSearchService;
import com.htthorizon.common.core.web.controller.BaseController;
import com.htthorizon.common.core.web.domain.AjaxResult;
import com.htthorizon.common.core.utils.poi.ExcelUtil;

/**
 * 模型查询条件配置Controller
 *
 * @author mark
 * @date 2023-11-27
 */
@RestController
@RequestMapping("/model/search")
@Slf4j
public class ModelSearchController extends BaseController
{
    @Autowired
    private IModelSearchService modelSearchService;

    @Autowired
    private IModelSourceService modelSourceService;

    @Autowired
    private IModelMetaService modelMetaService;

    @Autowired
    private IModelInfoService modelInfoService;

    @Autowired
    private SDKGetAPIUtil sdkGetAPIUtil;

    @Autowired
    private ServiceMarketHTTPUtil serviceMarketHTTPUtil;

    @Autowired
    private DataScopeUtil dataScopeUtil;

    @Autowired
    private ServiceMarket2HTTPUtil serviceMarket2HTTPUtil;

    /**
     * 查询模型查询条件配置列表
     */
    @RequiresPermissions("model:search:list")
    @GetMapping("/list")
    @Operate
    @Log(title = "模型管理/模型数据查看", businessType = BusinessType.QUERY)
    public AjaxResult list(@Valid ModelSearchReq modelSearch) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        ModelSource source = this.modelSourceService.selectModelSourceById(modelSearch.getSourceId());
        if(source == null){
            return error("数据源为空！");
        }
        AjaxResult ajax = AjaxResult.success();
        Map<String,String> metaMap = modelMetaService.getModelFieldsByModelId(modelSearch.getModelId());
        if(CollectionUtils.isEmpty(metaMap)){
            return error("获取模型的元数据信息为空！");
        }
        ajax.put("columnList", metaMap);
        Map<String,Object> paramsMap = new LinkedHashMap<>();
        //将查询条件封装成请求参数
        if(StringUtils.isNotEmpty(modelSearch.getSearchJson())){
            Map<String,Object> searchMap = JSON.parseObject(modelSearch.getSearchJson(),Map.class);
            if(StringUtils.isNotEmpty(searchMap)){
                for (String searchKey: searchMap.keySet()){
                    if(searchMap.get(searchKey)!=null && StringUtils.isNotEmpty(searchMap.get(searchKey).toString())) {
                        paramsMap.put(searchKey, String.valueOf(searchMap.get(searchKey)).trim());
                    }
                }
            }
        }
        String META_APPKEY=source.getAccount();
        String META_APPSECRE=source.getSecurityKey();
        String host = source.getHost();

        //请求远程API接口
//        HttpClientBuilderParams httpParam = new HttpClientBuilderParams();
//        httpParam.setAppKey(META_APPKEY);
//        httpParam.setAppSecret(META_APPSECRE);
//        sdkGetAPIUtil.init(httpParam);
//        ApiResponse metaDataByTb = sdkGetAPIUtil.searchByParams(source.getRequestUrl(),paramsMap);
//        String result=null;
//        if (metaDataByTb.getCode()==200){
//            result= new String(metaDataByTb.getBody(), StandardCharsets.UTF_8) ;
//        }
//      String result=  dataScopeUtil.getDataByUser(META_APPKEY, META_APPSECRE, source.getRequestUrl(), paramsMap);
//        String paramString1 = serviceMarket2HTTPUtil.getParamString(paramsMap);
//        String result = serviceMarket2HTTPUtil.getMethod(source.getRequestUrl(), paramString1);
        String paramString = serviceMarketHTTPUtil.getParamString(paramsMap);
        String result = serviceMarketHTTPUtil.getMethod(host,META_APPKEY, META_APPSECRE, source.getRequestUrl(), paramString);

//        log.info("result 查询: {}" , result1);
//        String result = dataScopeUtil.filterDataByDept(result1);
//        String result = TestDto.getModelData(); //测试数据
        log.info("result 查询: {}",result);


        if(StringUtils.isNotEmpty(result)) {
            Optional<RemoteDataInfoDto> dataOpt = null;
            try {
                JSONObject jsonObject = JSON.parseObject(result);
                dataOpt = Optional.ofNullable(JSONObject.parseObject(jsonObject.getString("data"), RemoteDataInfoDto.class));
            }catch (JSONException e){
                return error("获取远程模型数据json格式异常");
            }
            if (dataOpt.isPresent()) {
                RemoteDataInfoDto dataInfoDto = dataOpt.get();
                ajax.put("total",dataInfoDto.getTotalNum());
                ajax.put("tableDataInfo", dataInfoDto);
                List<?> dataList = dataInfoDto.getRows();
                //设置表头,获取api返回数据中的一条数据，设置中文字段表头
                if(StringUtils.isNotEmpty(dataList)) {
                    Map<String, Object> dataMap = (Map<String, Object>) dataList.get(0);
                    Map<String, Object> columnMap = new HashMap<>(dataMap.size());
                    for(String fieldName:dataMap.keySet()){
                        columnMap.put(fieldName,Optional.ofNullable(metaMap.get(fieldName)).orElse(""));
                    }
                    ajax.put("columnList", columnMap);
                }
            }else {
                return error("获取远程模型数据json格式异常");
            }
        }else{
            ajax.put("tableDataInfo", new RemoteDataInfoDto());
        }

        return ajax;
    }

    @Value("${downloadMaxNum}")
    private Integer MAX_NUM;

    @PostMapping("/download")
    @Operate(type=OperateType.DOWNLOAD)
    @Log(title = "模型管理/模型数据查看二次分析", businessType = BusinessType.EXPORT)
    public AjaxResult download(@Valid @RequestBody ModelSearchReq modelSearch, HttpServletResponse response) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        long start = System.currentTimeMillis();
        ModelSource source = this.modelSourceService.selectModelSourceById(modelSearch.getSourceId());
        if(source == null){
            return error("数据源为空！");
        }
        AjaxResult ajax = AjaxResult.success();
        Map<String,String> metaMap = modelMetaService.getModelFieldsByModelId(modelSearch.getModelId());
        if(CollectionUtils.isEmpty(metaMap)){
            return error("获取模型的元数据信息为空！");
        }
        ajax.put("columnList", metaMap);
        Map<String,Object> paramsMap = new LinkedHashMap<>();

        //将查询条件封装成请求参数
        if(StringUtils.isNotEmpty(modelSearch.getSearchJson())){
            Map<String,Object> searchMap = JSON.parseObject(modelSearch.getSearchJson(),Map.class);
            if(StringUtils.isNotEmpty(searchMap)){
                for (String searchKey: searchMap.keySet()){
                    if(searchMap.get(searchKey)!=null && StringUtils.isNotEmpty(searchMap.get(searchKey).toString())) {
                        paramsMap.put(searchKey, String.valueOf(searchMap.get(searchKey)).trim());
                    }
                }
            }
        }
        Map<String,Object>  paramsMapTemp=new HashMap<>(paramsMap);


        paramsMap.put("pageNum",1);
        paramsMap.put("pageSize",2000);
        String META_APPKEY=source.getAccount();
        String META_APPSECRE=source.getSecurityKey();
        String host = source.getHost();

        //请求远程API接口
//        HttpClientBuilderParams httpParam = new HttpClientBuilderParams();
//        httpParam.setAppKey(META_APPKEY);
//        httpParam.setAppSecret(META_APPSECRE);
//        sdkGetAPIUtil.init(httpParam);
//        ApiResponse metaDataByTb = sdkGetAPIUtil.searchByParams(source.getRequestUrl(),paramsMap);
//        String result=null;
//        if (metaDataByTb.getCode()==200){
//            result= new String(metaDataByTb.getBody(), StandardCharsets.UTF_8) ;
//        }
//      String result=  dataScopeUtil.getDataByUser(META_APPKEY, META_APPSECRE, source.getRequestUrl(), paramsMap);
        String paramString = serviceMarketHTTPUtil.getParamString(paramsMap);
        String result = serviceMarketHTTPUtil.getMethod(host,META_APPKEY, META_APPSECRE, source.getRequestUrl(), paramString);

//        log.info("result 查询: {}" , result1);
//        String result = dataScopeUtil.filterDataByDept(result1);
//        log.info("result 查询: {}",result);


        if(StringUtils.isNotEmpty(result)) {
            Optional<RemoteDataInfoDto> dataOpt = null;
            try {
                JSONObject jsonObject = JSON.parseObject(result);
                dataOpt = Optional.ofNullable(JSONObject.parseObject(jsonObject.getString("data"), RemoteDataInfoDto.class));
            }catch (JSONException e){
                return error("获取远程模型数据json格式异常");
            }
            List<List<?>> dataListAll = new ArrayList<>();
            if (dataOpt.isPresent()) {
                RemoteDataInfoDto dataInfoDto = dataOpt.get();
                ajax.put("tableDataInfo", dataInfoDto);
                ajax.put("total",dataInfoDto.getTotalNum());
                List<?> dataList = dataInfoDto.getRows();
                // 最大数大于总数  下载总数
                int dataTotal= MAX_NUM;
                if (dataInfoDto.getTotalNum() > MAX_NUM ){
                    throw new DownloadOverException();
                }else {
                    dataTotal=dataInfoDto.getTotalNum();
                }


                List<Map<String, Object>> pagination = this.pagination(dataTotal, 2000);
                log.info("分页的个数{}",pagination.size());
                long start2 = System.currentTimeMillis();
                for (Map<String,Object> page:pagination){
                        Map<String,Object>  paramsMapTemp2=new HashMap<>(paramsMapTemp);
                        log.info("pageNum{},pageSize{}",page.get("pageNum"),page.get("pageSize"));
                        paramsMapTemp2.put("pageNum",page.get("pageNum"));
                        paramsMapTemp2.put("pageSize",page.get("pageSize"));

                        String paramString2 = serviceMarketHTTPUtil.getParamString(paramsMapTemp2);
                        log.info("分页参数{}",paramString2);
                        String result2 = serviceMarketHTTPUtil.getMethod(host,META_APPKEY, META_APPSECRE, source.getRequestUrl(), paramString2);
//                        log.info("需要下载的数据{}",result2);
                        if(StringUtils.isNotEmpty(result2)) {
                            Optional<RemoteDataInfoDto> dataOpt2 = null;
                            try {
                                JSONObject jsonObject = JSON.parseObject(result2);
                                dataOpt2 = Optional.ofNullable(JSONObject.parseObject(jsonObject.getString("data"), RemoteDataInfoDto.class));
                            } catch (JSONException e) {
                                return error("获取远程模型数据json格式异常");
                            }
                            if (dataOpt2.isPresent()) {
                                RemoteDataInfoDto dataInfoDto2 = dataOpt2.get();
                                List<?> dataList2 = dataInfoDto2.getRows();
                                log.info("总条数1{}",dataInfoDto2.getRows().size());
                                dataListAll.add(dataList2);
                            }
                        }
                }
                long end2 = System.currentTimeMillis();
                log.info("请求数据耗时{}",(end2-start2));
                log.info("下载总数：{}",dataListAll.size());
                modelSearchService.download(response,dataListAll,modelSearch);
                //设置表头,获取api返回数据中的一条数据，设置中文字段表头
                if(StringUtils.isNotEmpty(dataList)) {
                    Map<String, Object> dataMap = (Map<String, Object>) dataList.get(0);
                    Map<String, Object> columnMap = new HashMap<>(dataMap.size());
                    for(String fieldName:dataMap.keySet()){
                        columnMap.put(fieldName,Optional.ofNullable(metaMap.get(fieldName)).orElse(""));
                    }
                    ajax.put("columnList", columnMap);
                }
            }else {
                return error("获取远程模型数据json格式异常");
            }
        }else{
            ajax.put("tableDataInfo", new RemoteDataInfoDto());
        }
        long end = System.currentTimeMillis();
        log.info("接口总耗时{}",(end-start));
        return ajax;
    }

    public List<Map<String,Object>> pagination(Integer total, Integer span){
        List<Map<String,Object>> pageList = new ArrayList<>();
        if (span >= total) {
            Map<String,Object> page = new HashMap<>();
            page.put("pageNum",1);
            page.put("pageSize",total);
            pageList.add(page);
            return pageList;
        }
        if (span < total) {
            long size = total / span;
            if (total % span != 0) {
                for (int i = 1; i <= size + 1; i++) {
                    Map<String,Object> page = new HashMap<>();
                    page.put("pageNum",i);
                    page.put("pageSize",span);
                    pageList.add(page);
                }
            } else {
                for (int i = 1; i <= size; i++) {
                    Map<String,Object> page = new HashMap<>();
                    page.put("pageNum",i);
                    page.put("pageSize",span);
                    pageList.add(page);
                }
            }

        }

        return pageList;
    }

    @PostMapping("/getDept")
    public AjaxResult getDept() {
        List<String> list=null;
        try {
            list =  modelSearchService.getDept();
        }catch (NullPointerException e){
            throw new NotDeptException();
        }

      return AjaxResult.success(list);
    }

    /**
     * 导出模型查询条件配置列表
     */
    @RequiresPermissions("model:search:export")
    @Log(title = "模型管理/模型查询条件配置", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @Operate(type = OperateType.DOWNLOAD)
    public void export(HttpServletResponse response, ModelSearch modelSearch)
    {
        List<ModelSearch> list = modelSearchService.selectModelSearchList(modelSearch);
        log.info("模型数据导出(二次分析):{}",list);

        ExcelUtil<ModelSearch> util = new ExcelUtil<ModelSearch>(ModelSearch.class);
        util.exportExcel(response, list, "模型数据导出");
        //更新模型使用次数
        this.modelInfoService.updateModelInfoUseCount(modelSearch.getModelId());
    }

    /**
     * 获取模型查询条件配置详细信息
     */
    @GetMapping(value = "/{modelId}")
    public AjaxResult getInfo(@PathVariable("modelId") Long modelId)
    {
        ModelSearch modelSearch = modelSearchService.selectModelSearchByModelId(modelId);
        return success(modelSearch);
    }

    /**
     * 新增模型查询条件配置
     */
    @RequiresPermissions("model:search:add")
    @Log(title = "模型管理/模型查询条件配置", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    public AjaxResult add(@Valid @RequestBody ModelSearch modelSearch)
    {
        return toAjax(modelSearchService.insertModelSearch(modelSearch));
    }

    /**
     * 修改模型查询条件配置
     */
    @RequiresPermissions("model:search:add")
    @Log(title = "模型管理/模型查询条件配置", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    public AjaxResult edit(@Valid @RequestBody ModelSearch modelSearch)
    {
        return toAjax(modelSearchService.updateModelSearch(modelSearch));
    }

    /**
     * 删除模型查询条件配置
     */
    @RequiresPermissions("model:search:remove")
    @Log(title = "模型管理/模型查询条件配置", businessType = BusinessType.DELETE)
    @PostMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids)
    {
        return toAjax(modelSearchService.deleteModelSearchByIds(ids));
    }
}
